#ifndef _TYPE_DEFINE_H_
#define _TYPE_DEFINE_H_

#ifndef __MSWIN__
# if defined (_WIN32) || defined (_WIN64)
#  define __MSWIN__ 1
# endif
#endif

#ifndef __LINUX__
# if defined (__linux__)
#  define __LINUX__ 1
# endif
#endif

#ifndef __DARWIN__
# if defined (__APPLE__) || defined (__apple__)
#  define __DARWIN__ 1
# endif
#endif

#ifndef __FREEBSD__
# if defined (__FreeBSD__)
#  define __FREEBSD__
# endif
#endif

#ifndef __BSD__
# if defined (__FreeBSD__) || defined (__DragonFly__) || defined (__NetBSD__) || defined (__APPLE__)
#  define __BSD__
# endif
#endif

#ifndef __KERNEL__
# ifdef KERNEL
#  define __KERNEL__
# endif
#endif

#ifndef __x86_64__
# if defined (__MSWIN__) && defined (_AMD64_)
#  define __x86_64__ 1
# elif defined (__DARWIN__) && defined (__LP64__)
#  define __x86_64__ 1
# endif
#endif

#if defined(_MSC_VER)
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;
typedef __int64 int64_t;
typedef unsigned long long uint64_t;
typedef unsigned long ptr32_t;
typedef unsigned long long ptr64_t;
#elif defined (__LINUX__) && defined (__KERNEL__)
# include <linux/types.h>
#else
# include <stdint.h>
#endif

#ifndef _MSC_VER
typedef uint32_t ptr32_t;
typedef uint64_t ptr64_t;
#endif

#ifdef _MSC_VER
# ifdef __x86_64__
typedef long long ssize_t;
# else
typedef long ssize_t;
# endif
#endif

#ifdef __MINGW32__
# include <_mingw.h>
#endif

#define __INT8_MIN	(-127-1)
#define __INT16_MIN	(-32767-1)
#define __INT32_MIN	(-2147483647-1)
#define __INT64_MIN	(-9223372036854775807LL-1LL)
#define __INT8_MAX	(+127)
#define __INT16_MAX	(+32767)
#define __INT32_MAX	(+2147483647)
#define __INT64_MAX	(+9223372036854775807LL)
#define __UINT8_MAX	(255)
#define __UINT16_MAX	(65535)
#define __UINT32_MAX	(4294967295U)
#define __UINT64_MAX	(18446744073709551615ULL)
#ifdef __x86_64__
# define __INTPTR_MAX	__INT64_MAX
#else
# define __INTPTR_MAX	__INT32_MAX
#endif
#ifdef __x86_64__
# define __UINTPTR_MAX	__UINT64_MAX
#else
# define __UINTPTR_MAX	__UINT32_MAX
#endif

/* boolean */
typedef long bool_t;

/* process id */
#ifdef _MSC_VER
typedef uint64_t pid_t;
#endif

/* relative pointer */
typedef int relptr_t;

/* utf-xx string */
typedef char utf8_t;
typedef uint16_t utf16_t;
typedef uint32_t utf32_t;

/* convert native pointer to relptr_t */
#define relptr(_natptr, _base_struct) ((relptr_t)((char *)(_natptr) - (char *)(_base_struct)))
#define mkrelptr(_natptr, _base_struct, _field) \
	do { \
		(_base_struct)->_field = relptr((_natptr), (_base_struct)); \
	} while (0)
/* convert relptr_t to native pointer */
#define natptr(_type, _base_struct, _field) ((_type)((char *)(_base_struct) + (_base_struct)->_field))

#define mkptr32(ptr) (ptr32_t) (uintptr_t) (ptr)
#define mkptr64(ptr) (ptr64_t) (uintptr_t) (ptr)
#define mku32(val) (uint32_t) (uintptr_t) (val)
#define mku64(val) (uint64_t) (uintptr_t) (val)
#define mkpid(val) (pid_t) (uintptr_t) (val)

#define LO8U(u16)  (uint8_t)   (u16)
#define HI8U(u16)  (uint8_t)  ((u16) >> 8)
#define LO16U(u32) (uint16_t)  (u32)
#define HI16U(u32) (uint16_t) ((u32) >> 16)
#define LO32U(u64) (uint32_t)  (u64)
#define HI32U(u64) (uint32_t) ((u64) >> 32)
#define MK16U(lo8,  hi8)  (( uint8_t) ( lo8) | (((uint16_t) ( hi8)) <<  8))
#define MK32U(lo16, hi16) ((uint16_t) (lo16) | (((uint32_t) (hi16)) << 16))
#define MK64U(lo32, hi32) ((uint32_t) (lo32) | (((uint64_t) (hi32)) << 32))

#define TAG32(str) (*(uint32_t *) (str))
#define TAG64(str) (*(uint64_t *) (str))

#define MKVER(major, minor) MK32U(minor, major)
// FIXME: do not use this name!
#if !defined(__LINUX__) || !defined (__KERNEL__)
# define MAJOR(version) HI16U(version)
# define MINOR(version) LO16U(version)
#endif

#if defined(__MSWIN__) || !defined(__KERNEL__)
# include <stddef.h>
# include <sys/types.h>
#endif

#ifndef __cplusplus
# ifndef true
#  define true 1L
# endif
# ifndef false
#  define false 0L
# endif
#endif

#if defined (__MSWIN__)
# define LL "I64"
#else
# if defined (__LINUX__) && defined (__x86_64__)
#  define LL "l"
# else
#  define LL "ll"
# endif
#endif
#define FMT_LL "%"LL

#ifndef MAX
# define MAX(a, b)  (((a) > (b)) ? (a) : (b))
#endif
#ifndef MIN
# define MIN(a, b)  (((a) < (b)) ? (a) : (b))
#endif

#ifdef _MSC_VER
# define __declspec_align(g) __declspec (align (g))
# define __declspec_thread(x) __declspec (thread) x
#else
# define __declspec_align(g) __attribute__ ((aligned (g)))
# define __declspec_thread(x) __thread x
#endif

/* Size Constants */
#define _1kb	0x00000400
#define _4kb	0x00001000
#define _32kb	0x00008000
#define _64kb	0x00010000
#define _128kb	0x00020000
#define _256kb	0x00040000
#define _512kb	0x00080000
#define _1mb	0x00100000
#define _2mb	0x00200000
#define _4mb	0x00400000
#define _1gb	0x40000000
#define _2gb32	0x80000000U
#define _2gb	0x0000000080000000LL
#define _4gb	0x0000000100000000LL
#define _1tb	0x0000010000000000LL
#define _1pb	0x0004000000000000LL
#define _1eb	0x1000000000000000LL
#define _2eb	0x2000000000000000ULL

/* handle unreferenced variables */
#define __unreferenced(x) x

#ifndef __forceinline__
# if defined(_MSC_VER) || defined(__MINGW32__)
#  define __forceinline__ __forceinline
# else
#  define __forceinline__ static inline
# endif
#endif

#if defined(_MSC_VER)
# define __inline__ __forceinline
# define __INLINE__ __forceinline static
#else
# define __INLINE__ static inline
#endif

#ifndef _MSC_VER
# define __in
# define __out
# define __in_opt
# define __out_opt
# define __out_bcount(x)
#endif

#ifdef __x86_64__
# define __CDECL
#else
# ifdef __GNUC__
#  define __CDECL __attribute__((cdecl))
# else
#  define __CDECL __cdecl
# endif
#endif
#define EXPORT_DECL __CDECL

#ifdef __x86_64__
# define __asmdecl
#else
# if defined(_MSC_VER)
#  define __asmdecl __cdecl
# else
#  define __asmdecl __attribute__((regparm(0)))
# endif
#endif

#ifdef _MSC_VER
# define ASMDECL(_RetType) _RetType __asmdecl
#else
# define ASMDECL(_RetType) __asmdecl _RetType
#endif

#ifndef glue
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
#endif

#ifndef likely
# if __GNUC__ < 3
# define __builtin_expect(x, n) (x)
# endif
# ifndef likely
#  define likely(x) __builtin_expect(!!(x), 1)
# endif
# ifndef unlikely
#  define unlikely(x) __builtin_expect(!!(x), 0)
# endif
#endif

#if __GNUC__ >= 4
# define DECL_VISIBILITY_DEFAULT __attribute__ ((visibility ("default")))
# define DECL_VISIBILITY_HIDDEN  __attribute__ ((visibility ("hidden")))
#else
# define DECL_VISIBILITY_DEFAULT
# define DECL_VISIBILITY_HIDDEN
#endif

#ifndef __MSWIN__
# define O_BINARY 0
# define O_TEXT 0
#endif

#define alignup(val, g)	(((val) + (g) - 1) & (~((g) - 1)))
#define aligndown(val, g) ((val) & (~((g) - 1)))

#ifndef offsetof
# define offsetof(type, member) (uintptr_t) &(((type *) 0)->member)
#endif

#if defined(__LINUX__) && defined(__KERNEL__)
# include <linux/kernel.h>
#else
# ifndef ARRAY_SIZE
#  define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
# endif
# ifndef container_of
#  define container_of(ptr, type, member) \
	((type *) ((char *) (ptr) - offsetof(type, member)))
# endif
#endif

#ifndef va_copy
# ifdef __va_copy
#  define va_copy(dst, src) __va_copy(dst, src)
# else
#  define va_copy(dst, src) ((dst) = (src))
# endif
#endif

/**
 * runtime library definations
 * ===========================
 */

#ifdef __MSWIN__
# define strtoll _strtoi64
# define strtoull _strtoui64
#else
# define stricmp strcasecmp
# define strnicmp strncasecmp
#endif

#if defined (_MSC_VER) && (_MSC_VER < 1900)
# define snprintf _snprintf
#endif

/* addtional O_XXX for I/O flags */
#define O_NOCACHE 0x80000000UL

/**
 * common data structure definations
 * =================================
 */

#ifdef __MSWIN__
# define DIR_DELIMIT '\\'
# define DIR_DELIMITS "\\"
#else
# define DIR_DELIMIT '/'
# define DIR_DELIMITS "/"
#endif

extern int kptr_size;

struct ip_addr {
	enum {
		IT_ipv4,
		IT_ipv6,
	} type;
	union{
		uint32_t ipv4;
		struct {
			uint8_t addr[16];
			uint32_t scope_id;
		} ipv6;
	};
};

enum mode_type {
	MT_user,
	MT_kernel,
};

enum address_mode {
	AM_32bit = sizeof(uint32_t),
	AM_64bit = sizeof(uint64_t),
};

#ifdef __x86_64__
# define KERNEL_HANDLE_MASK 0xffffffff80000000
#else
# define KERNEL_HANDLE_MASK 0x80000000
#endif

#define __kernel_handle(h) ((intptr_t)(h) < 0)
#define __make_kernel_handle(h) ((void *)((uintptr_t)(h) | KERNEL_HANDLE_MASK))

/* type of kernel callbacks */
enum kernel_callback_type {
	KCT_process = 0UL,
	KCT_thread,
	KCT_image,
	KCT_psnotify_limit,
	KCT_shutdown = KCT_psnotify_limit,
	// TODO:
	KCT_limit,
	KCT_cmapi = KCT_psnotify_limit,
	KCT_miniflt = KCT_psnotify_limit,
};

/* useful length definations */
#define MAX_NAME 1024
#define MAX_SRVNAME 128
#define MAX_FILENAME 128
#define MAX_SHORTNAME 128
#define MAX_PATHNAME 512
#define MAX_DEVNAME 256
#define MAX_CMDLINE 1024
#define MAX_KEYNAME 512
#define MAX_VALNAME 128
#define MAX_VALDATA 256

/**
 * compiler specific settings
 * ==========================
 */

/* disable some warnings for clang */
#ifdef __clang__
# pragma clang diagnostic ignored "-Wmicrosoft"
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif

/* memory barrier */
#if defined (_MSC_VER)
# ifdef __cplusplus
extern "C"
#endif
void _ReadWriteBarrier(void);
# pragma intrinsic(_ReadWriteBarrier)
# define __barrier__() do { _ReadWriteBarrier(); } while (0)
#elif defined (__GNUC__)
# define __barrier__() do { asm volatile("" ::: "memory"); } while (0)
#else
# define __barrier__() do {} while (0)
#endif

/* return address */
#ifndef __cplusplus
# if defined (_MSC_VER)
# ifdef __cplusplus
extern "C"
#endif
void *_ReturnAddress(void);
#  pragma intrinsic (_ReturnAddress)
#  define __builtin_retaddr() _ReturnAddress()
# elif defined (__GNUC__)
#  define __builtin_retaddr() __builtin_return_address(0)
# else
#  error unsupported compiler!
# endif
#endif

/**
 * utility routines
 * ================
 */

__INLINE__
int TOLOWER(int c)
{
	if (c >= 'A' && c <= 'Z')
		c += 'a' - 'A';
	return c;
}

__INLINE__
int TOUPPER(int c)
{
	if (c >= 'a' && c <= 'z')
		c += 'A' - 'a';
	return c;
}

#endif /* _TYPE_DEFINE_H_ */
